package com.haifeng.im.until;

import com.alibaba.fastjson.JSONObject;
import com.haifeng.im.message.Message;
import org.apache.ibatis.annotations.Update;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


public class WebSocketUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUtil.class);

    /**
     * Session 与用户的映射
     */
    private static final Map<WebSocketSession, String> SESSION_USER_MAP = new ConcurrentHashMap<>();
    /**
     * 用户与 Session 的映射
     */
    private static final Map<String, WebSocketSession> USER_SESSION_MAP = new ConcurrentHashMap<>();

    /**
     * 添加 Session 。在这个方法中，会添加用户和 Session 之间的映射
     *
     * @param session Session
     * @param user    用户
     */
    public static void addSession(WebSocketSession session, String user) {
            // 更新 USER_SESSION_MAP
            USER_SESSION_MAP.put(user, session);

            // 更新 USER_SESSION_MAP
            SESSION_USER_MAP.put(session, user);


    }


    /**
     * 移除session 映射
     *
     * @param session
     * @param user
     */
    public static void remveSession(WebSocketSession session, String user) {
        if (null != USER_SESSION_MAP.get(user)) {
            USER_SESSION_MAP.remove(user);
        }
        if (null != SESSION_USER_MAP.get(session)) {
            SESSION_USER_MAP.remove(session);
        }

    }


    /**
     * 发送消息给单个用户的 Session
     *
     * @param session Session
     * @param type    消息类型
     * @param message 消息体
     * @param <T>     消息类型
     */
    public static <T extends Message> void send(WebSocketSession session, String type, T message) {
        // 创建消息
        TextMessage messageText = buildTextMessage(type, message);
        // 遍历给单个 Session ，进行逐个发送
        if (SESSION_USER_MAP.containsKey(session))
            sendTextMessage(session, messageText);
    }

    /**
     * 发送消息给指定用户
     *
     * @param users    指定用户
     * @param type    消息类型
     * @param message 消息体
     * @param <T>     消息类型
     * @return 发送是否成功
     */
    public static <T extends Message> boolean sends(String type, T message,String...users) {
        // 获得用户对应的 Session
        for (String user:users){
            WebSocketSession session = USER_SESSION_MAP.get(user);
            if (session == null) {
                LOGGER.error("[send][user({}) 不存在对应的 session]", user);
                return false;
            }
            // 发送消息
            send(session, type, message);
            return true;
        }
        return true;
    }


    /**
     * 广播发送消息给所有在线用户
     *
     * @param type    消息类型
     * @param message 消息体
     * @param <T>     消息类型
     */
    public static <T extends Message> void broadcast(String type, T message) {
        // 创建消息
        TextMessage messageText = buildTextMessage(type, message);
        // 遍历 SESSION_USER_MAP ，进行逐个发送
        for (WebSocketSession session : SESSION_USER_MAP.keySet()) {
            sendTextMessage(session, messageText);
        }
    }





    /**
     * 构建完整的消息
     *
     * @param type    消息类型
     * @param message 消息体
     * @param <T>     消息类型
     * @return 消息
     */
    private static <T extends Message> TextMessage buildTextMessage(String type, T message) {
        JSONObject messageObject = new JSONObject();
        messageObject.put("type", type);
        messageObject.put("body", message);
        return new TextMessage(messageObject.toString());
    }

    /**
     * 真正发送消息
     *
     * @param session     Session
     * @param textMessage 消息
     */
    private static void sendTextMessage(WebSocketSession session, TextMessage textMessage) {
        if (session == null) {
            LOGGER.error("[sendTextMessage][session 为 null]");
            return;
        }
        try {
            session.sendMessage(textMessage);
        } catch (IOException e) {
            LOGGER.error("[sendTextMessage][session({}) 发送消息{}) 发生异常",
                    session, textMessage, e);
        }
    }
}
